package sg.nus.iss.vmcs.gui;

import java.util.Arrays;
import java.util.HashMap;

/**
 * Mediator / Observer to notify GUI on changing events.
 * @author Philip Chew
 */
public class GUIChangeManager {
	
	/** Hashmap acting as library of events and listeners */
	private HashMap<GUIChangeManagerEvent, GUIChangeObserver[]> library;
	
	/**
	 * Private Constructor
	 */
	private GUIChangeManager() {
		library = new HashMap<GUIChangeManagerEvent, GUIChangeObserver[]>();
	}
	
	/**
	 * Registers for a GUI Event
	 * @param eventName Name of Event to be notified
	 * @param o Observer to be registered
	 */
	public void registerEvent(GUIChangeManagerEvent eventName, GUIChangeObserver o) {
		if(library.containsKey(eventName)) {
			library.put(eventName, addToArray(o, library.get(eventName)));
		}
		else {
			library.put(eventName, new GUIChangeObserver[]{o});
		}
	}
	
	/**
	 * Fires an event, notifying all observers
	 * @param eventName Event to be fired
	 */
	public void fireEvent(GUIChangeManagerEvent eventName) {
		if(library.containsKey(eventName)) {
			for(GUIChangeObserver o : library.get(eventName)) {
				if(o != null)
					o.notifyEvent(eventName);
			}
		}
	}
	
	/**
	 * Fires an event, notifying all observers and providing additional parameters
	 * @param eventName Event to be fired
	 * @param params Parameters provided
	 */
	public void fireEvent(GUIChangeManagerEvent eventName, Object... params) {
		if(library.containsKey(eventName)) {
			for(GUIChangeObserver o : library.get(eventName)) {
				if(o != null)
					o.notifyEvent(eventName, params);
			}
		}
	}
	
	/**
	 * Adds a new observer to the GUIChangeObserver Array
	 * @param newObserver New Observer to be added
	 * @param curArray Current Array
	 * @return New array with new observer
	 */
	private GUIChangeObserver[] addToArray(GUIChangeObserver newObserver, GUIChangeObserver[] curArray) {
		GUIChangeObserver[] newArray = Arrays.copyOf(curArray, curArray.length + 1);
		newArray[newArray.length - 1] = newObserver;
		
		return newArray;
	}
	
	/**
	 * Returns an instance of the GUIChangeManager
	 * @return
	 */
	public static GUIChangeManager getInstance() {
		return GUIChangeManagerHolder.getGUIChangeManager();
	}
	
	/**
	 * Holder Class for GUIChangeManager Singleton. Prevents any synchronization issues.
	 */
	private static class GUIChangeManagerHolder {
		private static GUIChangeManager instance = null;
		
		public static GUIChangeManager getGUIChangeManager() {
			if(instance == null) instance = new GUIChangeManager();
			return instance;
		}
	}
}
